// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once


#include <cantor/parser/ast/base.h>
#include <cantor/parser/ast/expr.h>
#include <cantor/parser/ast/clause.h>
#include <cantor/parser/ast/func_when_clause.h>

namespace cantor::parser {

    struct FuncExpr : public DispatchExpr {
        static std::unordered_map<int, std::string> FUNC_STR_MAP;
        static std::unordered_map<int, const char *> FUNC_FN_NAME_MAP;
        String fn_name;
        pb::ast::FuncType func_type = pb::ast::FT_COMMON;
        bool is_not = false;
        bool distinct = false;
        bool is_star = false;
        Vector<DispatchExpr *> exprs;
        Vector<Indirection *> indirections;

        nlohmann::ordered_json to_json() const override;

        FuncExpr() : DispatchExpr(pb::ast::ENT_FUNC_EXPR, pb::ast::ExprNodeClass::ENC_FUNC) {
            fn_name = nullptr;
        }

        FuncExpr(pb::ast::FuncType t) : DispatchExpr(pb::ast::ENT_FUNC_EXPR, pb::ast::ExprNodeClass::ENC_FUNC), func_type(t) {
            fn_name = nullptr;
        }

        bool has_subquery() const;

        virtual void print() const override {
            std::cout << "func:" << func_type << " fn_name:" << fn_name << std::endl;
        }

        void to_stream(std::ostream &os) const override;

        static FuncExpr *new_unary_op_node(pb::ast::FuncType t, DispatchExpr *arg1, turbo::Arena &arena);

        static FuncExpr *new_binary_op_node(pb::ast::FuncType t, DispatchExpr *arg1, DispatchExpr *arg2, turbo::Arena &arena);

        static FuncExpr *new_ternary_op_node(pb::ast::FuncType t, DispatchExpr *arg1, DispatchExpr *arg2, DispatchExpr *arg3,
                                             turbo::Arena &arena);

        bool is_complex_node() override;

        static const char *type_to_name(pb::ast::FuncType t) {
            if (FUNC_FN_NAME_MAP.count(t) == 0) {
                return "unknown";
            }
            return FUNC_FN_NAME_MAP[t];
        }

        virtual bool is_complex_node_func() {
            return false;
        }
    };


    inline bool FuncExpr::is_complex_node() {
        if (is_complex) {
            return true;
        }
        for (int i = 0; i < exprs.size(); i++) {
            if (exprs[i]->is_complex_node()) {
                is_complex = true;
                return true;
            }
        }
        return false;
    }
} // namespace cantor::parser
